package com.superbytecode.stencil.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.superbytecode.stencil.entities.TemplateContext;
import com.superbytecode.stencil.entities.code.CodeContext;
import com.superbytecode.stencil.entities.DatasourceContext;
import com.superbytecode.stencil.entities.GeneratorReq;
import com.superbytecode.stencil.repository.domain.Datasource;
import com.superbytecode.stencil.repository.domain.TemplateGroup;
import com.superbytecode.stencil.wrapper.CodeEngineSelector;
import com.superbytecode.stencil.wrapper.CodeTemplateSelector;
import com.superbytecode.stencil.wrapper.DataSourceSelector;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.*;
import java.util.List;
import java.util.zip.ZipOutputStream;

/**
 * All rights Reserved, Designed By www.super-master.com
 *
 * @ProjectName: code-stencil
 * @Package: com.superbytecode.stencil.service
 * @ClassName: CodeGeneratorService
 * @Description: []
 * <p> </p>
 * @Author: [Lance Ting]
 * @Date: 2024/10/11 19:41
 * @Version: V1.0
 * @Copyright: 2024 www.super-master.cn Inc. All rights reserved.
 * TODO: 注意,本文件Lance Ting所作,如果转载或使用请标明具体出处!
 **/
@Slf4j
@Service
public class CodeGeneratorService {
    @Resource
    private DatasourceService datasourceService;
    @Resource
    private TemplateGroupService templateGroupService;

    /**
     * 使用本地模板生成代码
     *
     * @param generatorReq 参数
     * @return 结果
     */
    public CodeContext createCodeForStandard(GeneratorReq generatorReq) {
        CodeContext codeContext = new CodeContext();
        // 1、参数解析
        Long datasourceId = generatorReq.getDatasourceId();
        // 2、数据源上下文DatasourceContext对象
        Datasource datasource = datasourceService.obtainDatasource(datasourceId);
        DatasourceContext context = DataSourceSelector.builder(datasource).build();
        // 设置指定表，默认为空
        if (CollectionUtil.isNotEmpty(generatorReq.getSchTableNames())) {
            context.setSchTableNames(generatorReq.getSchTableNames().toArray(new String[0]));
        }
        context.setPrefix(generatorReq.getPrefix());
        // 3、获取表和列结构信息
        TemplateGroup templateGroup = templateGroupService.obtainTemplateGroup(datasource.getGroupId());
        log.info("template group: {}", JSONUtil.toJsonStr(templateGroup));
        List<TemplateContext> properties = CodeTemplateSelector.builder(context, templateGroup).build();
        log.info("properties :{}", JSONUtil.toJsonStr(properties));
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream zip = new ZipOutputStream(outputStream);
        properties.forEach(p -> {
            CodeEngineSelector.builder(zip).createForVelocity(p);
        });
        IOUtils.closeQuietly(zip);
        byte[] data = outputStream.toByteArray();
        String fileName = templateGroup.getFileName();
        String filePath = templateGroup.getFilePath();
        this.saveZipFileForCode(data, fileName, filePath);
        //
        codeContext.setContent(data);
        codeContext.setFolder(filePath);
        codeContext.setFileName(fileName);
        return codeContext;
    }

    /**
     * 使用数据库配置模板生成代码
     *
     * @param generatorReq 参数
     * @return 结果
     */
    public List<CodeContext> createCodeForCustomized(GeneratorReq generatorReq) {
        return null;
    }

    public void saveZipFileForCode(byte[] data, String fileName, String filePath) {
        File directory = new File(filePath);
        if (!directory.exists() && !directory.mkdirs()) {
            throw new IllegalArgumentException("create directory error");
        }
        filePath = filePath + File.separator + fileName; // 要保存的文件路径
        try (FileOutputStream fos = new FileOutputStream(filePath)) {
            fos.write(data);
            System.out.println("文件保存成功，路径：" + filePath);
        } catch (IOException e) {
            System.out.println("文件保存失败：" + e.getMessage());
        }
    }

}